using System.Text.Json.Nodes;
using AntChain.SDK.ATO;
using AntChain.SDK.ATO.Models;
using Vin.Extension.Framework.AntChain.Models;
using Vin.Extension.Framework.AntChain.Models.Req;
using Vin.Extension.Framework.AntChain.Options;
using Vin.Extension.Framework.AntChain.Tools;
using Vin.Extension.Framework.Base;
using Vin.Extension.NLog;
using Vin.Tool.AspNetCore.Singleton;
using Vin.Tool.Core.AssertCategory;
using Vin.Tool.Core.JsonCategory;

namespace Vin.Extension.Framework.AntChain.Service;

public class VinAntChainBaseService : VinFrameworkBaseService
{
    public const string LoggerTag = "AntChain";
    protected VinAntChainConfig _chainConfig => VinApp.GetConfig<VinAntChainConfig>();

    public string Env => _chainConfig.Env;

    public string TenantId =>
        _chainConfig.TenantId ?? throw new ArgumentNullException(nameof(_chainConfig.TenantId));

    public string PublicKey =>
        _chainConfig.RsaPublicKey ?? throw new ArgumentNullException(nameof(_chainConfig.RsaPublicKey));

    public string MerchantId =>
        _chainConfig.MerchantId ?? throw new ArgumentNullException(nameof(_chainConfig.MerchantId));

    public string MerchantName =>
        _chainConfig.MerchantName ?? throw new ArgumentNullException(nameof(_chainConfig.MerchantName));

    public string MerchantAddress =>
        _chainConfig.MerchantAddress ?? throw new ArgumentNullException(nameof(_chainConfig.MerchantAddress));

    public string MerchantAlipayUid =>
        _chainConfig.MerchantAlipayUid ?? throw new ArgumentNullException(nameof(_chainConfig.MerchantAlipayUid));

    public Client Client => new(_chainConfig);

    #region 商品

    /// <summary>
    /// 同步商品
    /// </summary>
    public async Task<SyncTradeResponse> SyncProductAsync(ProductInfoReq productInfo)
    {
        productInfo.MerchantId = MerchantId;
        var req = new SyncTradeRequest()
        {
            Type = "product",
            BizContent = productInfo.ToCamelCaseJson(),
        };
        var res = await Client.SyncTradeAsync(req);

        Logger.Info(LoggerTag, string.Format("蚂蚁链同步商品请求报文{0}，结果：{1}", req.ToJson(), res.ToJson()));

        return res;
    }

    #endregion

    #region 订单

    /// <summary>
    /// 同步后置订单
    /// </summary>
    public async Task<SyncTradeResponse> SyncBehindOrderAsync(OrderFullInfoReq orderFullInfoReq)
    {
        orderFullInfoReq.MerchantId = MerchantId;
        orderFullInfoReq.MerchantName = MerchantName;
        if (orderFullInfoReq.UserInfo != null)
        {
            if (orderFullInfoReq.UserInfo.UserName.IsNotNullOrEmpty())
                orderFullInfoReq.UserInfo.UserName =
                    AntChainTool.AntChainEncrypt(orderFullInfoReq.UserInfo.UserName!, PublicKey);
            if (orderFullInfoReq.UserInfo.UserPhoneNumber.IsNotNullOrEmpty())
                orderFullInfoReq.UserInfo.UserPhoneNumber =
                    AntChainTool.AntChainEncrypt(orderFullInfoReq.UserInfo.UserPhoneNumber!, PublicKey);
            if (orderFullInfoReq.UserInfo.UserId.IsNotNullOrEmpty())
                orderFullInfoReq.UserInfo.UserId =
                    AntChainTool.AntChainEncrypt(orderFullInfoReq.UserInfo.UserId!, PublicKey);
        }

        var req = new SyncTradeRequest()
        {
            Type = "orderFullInfo",
            BizContent = orderFullInfoReq.ToCamelCaseJson(),
        };
        var res = await this.Client.SyncTradeAsync(req);

        Logger.Info(LoggerTag, $"蚂蚁链同步订单请求报文{req.ToJson()}，结果：{res.ToJson()}");

        return res;
    }

    /// <summary>
    /// 关闭订单
    /// </summary>
    public async Task<SyncTradeResponse> CloseOrderAsync(string orderId, bool unbind = false, string closeReason = "")
    {
        var req = new SyncTradeRequest()
        {
            Type = "closeOrder",
            BizContent = new
            {
                orderId,
                closeReason
            }.ToJson(),
        };
        var res = await this.Client.SyncTradeAsync(req);

        Logger.Info(LoggerTag, $"蚂蚁链关闭订单请求报文{req.ToJson()}，结果：{res.ToJson()}");

        if (unbind)
        {
            await WithholdUnbindAsync(new UnbindWithholdSignRequest()
            {
                OrderId = orderId
            });
        }

        return res;
    }

    /// <summary>
    /// 查询订单履约记录
    /// </summary>
    public async Task<object?> QueryOrderFulfillmentAsync(string orderId, int? termIdx = null)
    {
        var req = new GetTradeRequest()
        {
            Type = "fulfillment",
            BizContent = new
            {
                orderId,
                termIdx,
            }.ToJson(),
        };
        var res = await this.Client.GetTradeAsync(req);

        Logger.Info(LoggerTag, $"蚂蚁链查询订单履约记录请求报文{req.ToJson()}，结果：{res.ToJson()}");

        return JsonNode.Parse(res.ResponseData);
    }

    /// <summary>
    /// 查询用户履约信息
    /// </summary>
    /// <param name="orderId"></param>
    /// <returns></returns>
    public async Task<object?> QueryUserPerformanceAsync(string orderId)
    {
        var req = new GetTradeUserperformanceRequest()
        {
            OrderId = orderId,
            MerchantId = MerchantId
        };
        var res = await this.Client.GetTradeUserperformanceAsync(req);
        Logger.Info(LoggerTag, $"蚂蚁链查询用户履约记录请求报文{req.ToJson()}，结果：{res.ToJson()}");
        return JsonNode.Parse(res.ResponseData);
    }

    #endregion

    #region 合同

    /// <summary>
    /// 查询全部签署模板
    /// </summary>
    /// <returns></returns>
    public async Task<AllSignTemplateResponse> QueryAllSignTemplateAsync()
    {
        var req = new AllSignTemplateRequest()
        {
            MerchantId = MerchantId
        };
        var res = await this.Client.AllSignTemplateAsync(req);

        Logger.Info(LoggerTag, $"蚂蚁链查询全部签署模板请求报文{req.ToJson()}，结果：{res.ToJson()}");

        return res;
    }

    /// <summary>
    /// 后置签署合同
    /// </summary>
    public async Task<SubmitSignFlowResponse> SubmitBehindSignFlowAsync(SubmitSignFlowReq req)
    {
        if (req.MerchantName.IsNullOrEmpty())
            req.MerchantName = MerchantName;
        if (req.MerchantIdNumber.IsNullOrEmpty())
            req.MerchantIdNumber = MerchantId;
        if (req.MerchantIdType.IsNullOrEmpty())
            req.MerchantIdType = "CRED_ORG_USCC";

        if (req.UserIdNumber.IsNotNullOrEmpty())
            req.UserIdNumber = AntChainTool.AntChainEncrypt(req.UserIdNumber, PublicKey);
        if (req.UserName.IsNotNullOrEmpty())
            req.UserName = AntChainTool.AntChainEncrypt(req.UserName, PublicKey);
        if (req.UserMobile.IsNotNullOrEmpty())
            req.UserMobile = AntChainTool.AntChainEncrypt(req.UserMobile, PublicKey);
        if (req.UserEmail.IsNotNullOrEmpty())
            req.UserEmail = AntChainTool.AntChainEncrypt(req.UserEmail, PublicKey);
        if (req.MerchantIdNumber.IsNotNullOrEmpty())
            req.MerchantIdNumber = AntChainTool.AntChainEncrypt(req.MerchantIdNumber, PublicKey);
        if (req.MerchantLegalName.IsNotNullOrEmpty())
            req.MerchantLegalName = AntChainTool.AntChainEncrypt(req.MerchantLegalName, PublicKey);
        if (req.MerchantLegalIdNumber.IsNotNullOrEmpty())
            req.MerchantLegalIdNumber = AntChainTool.AntChainEncrypt(req.MerchantLegalIdNumber, PublicKey);
        if (req.ThirdSignerList is { Count: > 0 })
        {
            req.ThirdSignerList.ForEach(item =>
            {
                if (item.OrgIdNumber.IsNotNullOrEmpty())
                    item.OrgIdNumber = AntChainTool.AntChainEncrypt(item.OrgIdNumber!, PublicKey);
                if (item.OrgLegalName.IsNotNullOrEmpty())
                    item.OrgLegalName = AntChainTool.AntChainEncrypt(item.OrgLegalName!, PublicKey);
                if (item.OrgLegalIdNumber.IsNotNullOrEmpty())
                    item.OrgLegalIdNumber = AntChainTool.AntChainEncrypt(item.OrgLegalIdNumber!, PublicKey);
            });
            req.ThirdSigner = req.ThirdSignerList.ToCamelCaseJson();
            req.ThirdSignerList = null;
        }

        if (req.TemplateModelList is { Count: > 0 })
        {
            req.TemplateList = req.TemplateModelList.ToCamelCaseJson();
            req.TemplateModelList = null;
        }

        var res = await this.Client.SubmitSignFlowAsync(req);
        Logger.Info(LoggerTag, $"蚂蚁链后置签署合同请求报文{req.ToJson()}，结果：{res.ToJson()}");
        return res;
    }

    /// <summary>
    /// 查询签署流程
    /// </summary>
    public async Task<GetSignFlowResponse> QuerySignFlowAsync(string signNo)
    {
        var req = new GetSignFlowRequest()
        {
            SignNo = signNo
        };
        var res = await this.Client.GetSignFlowAsync(req);
        Logger.Info(LoggerTag, $"蚂蚁链查询签署流程请求报文{req.ToJson()}，结果：{res.ToJson()}");
        return res;
    }

    #endregion

    #region 代扣签约

    /// <summary>
    /// 代扣签约
    /// </summary>
    public async Task<CreateWithholdSignResponse> WithholdSignAsync(CreateWithholdSignRequest req)
    {
        var res = await this.Client.CreateWithholdSignAsync(req);
        Logger.Info(LoggerTag, $"蚂蚁链代扣签约请求报文{req.ToJson()}，结果：{res.ToJson()}");
        return res;
    }

    /// <summary>
    /// 代扣解约
    /// </summary>
    public async Task<UnbindWithholdSignResponse> WithholdUnbindAsync(UnbindWithholdSignRequest req)
    {
        var res = await this.Client.UnbindWithholdSignAsync(req);
        Logger.Info(LoggerTag, $"蚂蚁链代扣解约请求报文{req.ToJson()}，结果：{res.ToJson()}");
        return res;
    }

    /// <summary>
    /// 未到期代扣批量取消
    /// </summary>
    /// <returns></returns>
    public async Task<CancelWithholdPlanResponse> BatchCancelWithholdAsync(CancelWithholdPlanRequest req)
    {
        var res = await this.Client.CancelWithholdPlanAsync(req);
        Logger.Info(LoggerTag, $"蚂蚁链未到期代扣批量取消请求报文{req.ToJson()}，结果：{res.ToJson()}");
        return res;
    }

    /// <summary>
    /// 单期代扣取消
    /// </summary>
    public async Task<RepayWithholdPlanResponse> CancelWithholdAsync(RepayWithholdPlanRequest req)
    {
        req.GmtPay = DateTime.Now.ToString("yyyy-MM-ddTHH:mm:sszzz");
        var res = await this.Client.RepayWithholdPlanAsync(req);
        Logger.Info(LoggerTag, $"蚂蚁链单期代扣取消请求报文{req.ToJson()}，结果：{res.ToJson()}");
        return res;
    }

    /// <summary>
    /// 代扣退款
    /// </summary>
    /// <param name="orderId">合约id</param>
    /// <param name="periodNum">期数</param>
    /// <param name="refundRequestNo">退款请求单号</param>
    /// <param name="refundMoney">退款金额</param>
    /// <param name="refundReason">退款原因</param>
    /// <returns></returns>
    public async Task<CreateWithholdRefundResponse> WithholdRefundAsync(string orderId, int periodNum,
        string refundRequestNo, decimal refundMoney, string? refundReason)
    {
        var req = new CreateWithholdRefundRequest()
        {
            OrderId = orderId,
            PeriodNum = periodNum,
            RefundRequestNo = refundRequestNo,
            RefundMoney = (long)(refundMoney * 100),
            RefundReason = refundReason
        };
        var res = await this.Client.CreateWithholdRefundAsync(req);
        Logger.Info(LoggerTag, $"蚂蚁链代扣退款请求报文{req.ToJson()}，结果：{res.ToJson()}");
        return res;
    }

    /// <summary>
    /// 查询代扣退款
    /// </summary>
    /// <param name="orderId"></param>
    /// <param name="periodNum"></param>
    /// <param name="no"></param>
    public async Task<QueryWithholdRefundResponse> QueryWithholdRefundAsync(string orderId, int periodNum, string no)
    {
        var req = new QueryWithholdRefundRequest()
        {
            OrderId = orderId,
            PeriodNum = periodNum,
            RefundRequestNo = no,
        };
        var res = await this.Client.QueryWithholdRefundAsync(req);
        Logger.Info(LoggerTag, $"蚂蚁链查询代扣退款请求报文{req.ToJson()}，结果：{res.ToJson()}");
        return res;
    }

    #endregion

    #region 风控

    /// <summary>
    /// 风控查询
    /// </summary>
    /// <param name="req"></param>
    /// <returns></returns>
    public async Task<QueryRiskResponse> QueryRiskAsync(QueryRiskRequest req)
    {
        if (req.UserName.IsNotNullOrEmpty()) req.UserName = AntChainTool.AntChainEncrypt(req.UserName, PublicKey);
        if (req.CertNo.IsNotNullOrEmpty()) req.CertNo = AntChainTool.AntChainEncrypt(req.CertNo, PublicKey);
        if (req.Mobile.IsNotNullOrEmpty()) req.Mobile = AntChainTool.AntChainEncrypt(req.Mobile, PublicKey);
        var res = await this.Client.QueryRiskAsync(req);

        Logger.Info(LoggerTag, $"蚂蚁链风控请求报文{req.ToJson()}，结果：{res.ToJson()}");

        return res;
    }

    #endregion
}